const bcrypt = require('bcryptjs')
const { getUserinfo } = require("../service/user.service")
const { usernameOrPasswordIsNull, usernameAlreayExisted, serverError, usernameNoExisted, invalidPassword, tokenExpired, invalidToken } = require('../constants/error.type')
const jwt = require('jsonwebtoken')
const { PRIVATE_KEY } = require('../config')

const userValidator = async (ctx, next) => {
  let { username, password } = ctx.request.body
  username = String(username).trim()
  password = String(password).trim()
  if (!username || !password) {
    return ctx.app.emit('error', usernameOrPasswordIsNull, ctx)
  }

  await next()
}

const verifyUser = async (ctx, next) => {
  const { username } = ctx.request.body
  try {
    const userinfo = await getUserinfo({ username })
    if (userinfo) {
      return ctx.app.emit('error', usernameAlreayExisted, ctx)
    }
  } catch (err) {
    console.error('verifyUser错误：', err, { username })
    return ctx.app.emit('error', serverError, ctx)
  }

  await next()
}

const cryptPassword = async (ctx, next) => {
  const { password } = ctx.request.body
  const salt = bcrypt.genSaltSync(10)
  const hash = bcrypt.hashSync(password, salt)
  ctx.request.body.password = hash

  await next()
}

const verifyLogin = async (ctx, next) => {
  const { username, password } = ctx.request.body

  try {
    const result = await getUserinfo({ username })
    if (!result) {
      return ctx.app.emit('error', usernameNoExisted, ctx)
    }
    if (!bcrypt.compareSync(password, result.password)) {
      return ctx.app.emit('error', invalidPassword, ctx)
    }
  } catch (err) {
    console.error('verifyLogin', err, { username, password })
    return ctx.app.emit('error', serverError, ctx)
  }

  await next()
}

const verifyToken = async (ctx, next) => {
  const { authorization } = ctx.request.headers
  const token = String(authorization).replace(/^Bearer\s/, '')

  try {
    const { id } = jwt.verify(token, PRIVATE_KEY)
    const userinfo = await getUserinfo({ userId: id })
    ctx.state.userinfo = userinfo
    if (!userinfo) return ctx.app.emit('error', invalidToken, ctx)
  } catch (err) {
    // err
    console.error('[reset password error]: ', err)
    switch (err.name) {
      case jwt.TokenExpiredError.name:
        return ctx.app.emit('error', tokenExpired, ctx)
      case jwt.JsonWebTokenError.name:
        return ctx.app.emit('error', invalidToken, ctx)
      default:
        return ctx.app.emit('error', serverError, ctx)
    }
  }

  await next()
}

module.exports = {
  userValidator,
  verifyUser,
  cryptPassword,
  verifyLogin,
  verifyToken
}
